package folder.model.link;

import java.util.List;

import folder.model.network.Network;
import folder.model.network.NetworkPaths;
import folder.model.node.Node;
import folder.model.virtual.VirtualLink;
import folder.model.virtual.VirtualNetwork;
import folder.model.virtual.VirtualNode;

public class LinkAllocation
{
	private List< Node > nodes;
	private List< Link > links;
	private Network network;
	
	public LinkAllocation( Network network )
	{
		this.network = network;
		this.links = network.getLinks();
		this.nodes = network.getNodes();
	}
	
	// Allocation
	
	double delayVirtualLink;
	private List< Link > linksVirtualLink;
	
	public boolean allocateVirtualLinks( List< VirtualLink > virtualLinks )
	{
        for( VirtualLink virtualLink: virtualLinks )
        	if( !this.allocateVirtualLink( virtualLink ) )
        		return false;
        
        return true;
	}
	
	private boolean allocateVirtualLink( VirtualLink virtualLink )
	{
		this.connectLinks();
    	this.disconnectLinks( virtualLink );
    	this.setPath( virtualLink );
    	this.connectLinks();
    	
    	if( this.checkDelay() )
    	{
    		this.allocateVirtualLinkToLinks( virtualLink );
    		this.allocateLinksToVirtualLink( virtualLink );
    		
    		return true;
    	}
    	
    	return false;
	}
	
	private void connectLinks()
	{
		for( Link link: this.links )
			link.connect();
	}
	
	private void disconnectLinks( VirtualLink virtualLink )
	{
		this.disconnectLinksWithoutBandwidth( virtualLink.getBandwidth() );
		this.disconnectLinksOfControllers();
	}
	
	private void disconnectLinksWithoutBandwidth( double bandwidth )
	{
		for( Link link: this.links )
			if( link.getBandwidthAvailable() < bandwidth )
				link.disconnect();
	}
	
	private void disconnectLinksOfControllers()
	{
		for( Node node: this.nodes )
			if( node.isSelected() )
				node.disconnectLinks();
	}
	
	private void setPath( VirtualLink virtualLink )
	{
    	VirtualNode virtualNodeA = virtualLink.getVirtualNodeA();
    	VirtualNode virtualNodeB = virtualLink.getVirtualNodeB();
    	
		Node nodeA = virtualNodeA.getNode();
		Node nodeB = virtualNodeB.getNode();
		
		this.network.setPathsNode( nodeA );
		
		this.delayVirtualLink = nodeA.getDelayToNodeTarget( nodeB );
		this.linksVirtualLink = nodeA.getLinksToNodeTarget( nodeB );
	}
	
	private boolean checkDelay()
	{
		if( this.delayVirtualLink < Double.POSITIVE_INFINITY )
			return true;
		else
			return false;
	}
	
	private void allocateVirtualLinkToLinks( VirtualLink virtualLink )
	{
  		for( Link link: linksVirtualLink )
		{
			link.allocateBandwidthAvailable( virtualLink.getBandwidth() );
			link.addVirtualLink( virtualLink );
		}
	}
	
	private void allocateLinksToVirtualLink( VirtualLink virtualLink )
	{
		for( Link link: linksVirtualLink )
			virtualLink.addLink( link );
	}

}
